package com.tlgen.spring.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.tlgen.spring.annotation.Autowired;
import com.tlgen.spring.annotation.Value;
import com.tlgen.spring.model.BeanDefinition;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

import static com.tlgen.spring.utils.YmlUtils.getValueFromYml;

public class SpeedSpringReflectionUtils {

    /**
     * 调用被 @Bean 标注的方法, 创建对应的 Bean 类型
     *
     * @param className
     * @param beanClassName
     * @return
     */
    public static Object invokeBeanMethod(String className, String beanClassName) {
        Object result = null;
        try {
            Class<?> aClass = Class.forName(className);
            Object instance = aClass.newInstance();
            for (Method declaredMethod : aClass.getDeclaredMethods()) {
                // 根据返回类型判断
                if (Objects.equals(beanClassName, declaredMethod.getReturnType().getTypeName())) {
                    declaredMethod.setAccessible(true);
                    result = declaredMethod.invoke(instance);
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 根据接口获取实现类对象
     *
     * @param interfaceClassName
     * @return
     */
    public static Object newInstanceInterface(List<BeanDefinition> beanDefinitionList, String interfaceClassName) {
        try {
            Class<?> clazz = Class.forName(interfaceClassName);
            // 如果是接口类, 找到它的实现类, 实现类才可以被实例化
            List<String> implClassesByInterfaceClass = ScanUtils.getImplClassesByInterfaceClass(clazz);
            if (CollectionUtil.isNotEmpty(implClassesByInterfaceClass)) {
                String className = implClassesByInterfaceClass.get(0);
                Class<?> implClazz;
                Object implInstance;
                try {
                    implClazz = Class.forName(className);
                    implInstance = implClazz.newInstance();
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
                // 为接口类对应的实现类进行属性赋值
                for (Field declaredField : implClazz.getDeclaredFields()) {
                    declaredField.setAccessible(true);
                    Value annotation = declaredField.getAnnotation(Value.class);
                    if (Objects.nonNull(annotation)) {
                        // 根据 yml 文件配置获取属性值
                        Object valueFromYml = getValueFromYml(annotation);
                        declaredField.set(implInstance, valueFromYml);
                    }
                    // @Autowired 注入引用的 Bean
                    Autowired autowiredAnnotation = declaredField.getAnnotation(Autowired.class);
                    if (Objects.nonNull(autowiredAnnotation)) {
                        Class<?> type = declaredField.getType();
                        String innerInterfaceClassName = type.getTypeName(); // 一定是接口类型
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setBeanName(StringUtils.getSimpleClassName(innerInterfaceClassName));
                        beanDefinition.setClassName(innerInterfaceClassName);
                        // 如果从单例池中没有找到, 那么直接创建, 因为有可能是其他 bean 在初始化时引用了这个接口 bean, 已经创建过
                        Object object = SpeedSpringContextUtils.getBean(type);
                        if (Objects.nonNull(object)) {
                            declaredField.set(implInstance, object);
                            beanDefinition.setInstance(object);
                        } else {
                            // 如果是接口类型, 直接找到接口的实现类进行实例化
                            Object interfaceInstance = newInstanceInterface(beanDefinitionList, innerInterfaceClassName);
                            declaredField.set(implInstance, interfaceInstance);
                            beanDefinition.setInstance(interfaceInstance);
                        }
                        beanDefinitionList.add(beanDefinition);
                    }
                }
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanName(StringUtils.getSimpleClassName(interfaceClassName));
                beanDefinition.setClassName(interfaceClassName);
                beanDefinition.setInstance(implInstance);
                beanDefinitionList.add(beanDefinition);
                return implInstance;
            }
        } catch (ClassNotFoundException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

}
